#pragma once
/***********************************************************************************************
COPYRIGHT 2011 Mafahir Fairoze

This file is part of Neural++.
(Project Website : http://mafahir.wordpress.com/projects/neuralplusplus)

Neural++ is a free software. You can redistribute it and/or modify it under the terms of
the GNU General Public License as published by the Free Software Foundation, either version 3
of the License, or (at your option) any later version.

Neural++ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License <http://www.gnu.org/licenses/> for more details.

***********************************************************************************************/


#include <vector>
#include "INeuron.h"
#include "Connector.h"
#include "AbstractFunction.h"
#include "IInitializer.h"


namespace NeuralPlusPlus
	{
	namespace Core        
		{
		class INeuron;
		class Connector;
		class IInitializer;

		using namespace NeuralPlusPlus::Core::LearningRateFunctions;

		/// <summary>
		/// Layer is an abstract container for similar neurons. No two neurons within a layer can be
		/// connected to each other.
		/// </summary>
		class Layer abstract
			{
			/// <summary>
			/// Array of neurons in the layer. This is never <c>NULL</c>.
			/// </summary>
			public: INeuron **Neurons;
			public: int NeuronsLength;

					/// <summary>
					/// List of source connectors. This read-only value is never <c>NULL</c>.
					/// </summary>
			public: std::vector<Connector*> SourceConnectors;

					/// <summary>
					/// List of target connectors. This read-only value is never <c>NULL</c>.
					/// </summary>
			public: std::vector<Connector*> TargetConnectors;

					/// <summary>
					/// Learning Rate Function
					/// </summary>
			public: AbstractFunction *LearningRateFunction;

					/// <summary>
					/// Initializer used to initialize the layer. If this->value is <c>NULL</c>, neurons will have
					/// default values for initializable parameters (usually zero)
					/// </summary>
			public: IInitializer *Initializer;

					   /// <summary>
					   /// Neuron Indexer
					   /// </summary>
			public: INeuron* operator[](int index);

					/// <summary>
					/// Gets the initial value of learning rate
					/// </summary>
			public: double LearningRate();

					/// <summary>
					/// Creates a new layer
					/// </summary>
			protected: Layer(int neuronCount);

					   /// <summary>
					   /// Sets neuron inputs to the values specified by the given array
					   /// </summary>
			public: virtual void SetInput(double* input);

					/// <summary>
					/// Gets the neuron outputs as an array
					/// </summary>
			public: virtual double* GetOutput();

					/// <summary>
					/// Sets the learning rate to the given value. The layer will use this->constant value
					/// as learning rate throughout the learning process
					/// </summary>
			public: void SetLearningRate(double learningRate);

					/// <summary>
					/// Sets the initial and final values for learning rate. During the learning process, the
					/// effective learning rate uniformly changes from its initial value to final value
					/// </summary>
			public: void SetLearningRate(double initialLearningRate, double finalLearningRate);

					/// <summary>
					/// Sets the learning rate function.
					/// </summary>
			public: void SetLearningRate(AbstractFunction *learningRateFunction);

					/// <summary>
					/// Initializes all neurons and makes them ready to undergo training freshly.
					/// </summary>
			public: virtual void Initialize() = 0;

					/// <summary>
					/// Runs all neurons in the layer.
					/// </summary>
			public: virtual void Run();

					/// <summary>
					/// All neurons and their are source connectors are allowed to learn. This method assumes a
					/// learning environment where inputs, outputs and other parameters (if any) are appropriate.
					/// </summary>
			public: virtual void Learn(int currentIteration, int trainingEpochs);

					/// <summary>
					/// Deallocates memory.
					/// </summary>
			public: virtual ~Layer();
			};
		}    
	}